# encoding:utf8
import os
import time
import traceback

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.options import Options
# 注意如果有类名相同, 可以用as来别名区分要不然会报错
from selenium.webdriver.firefox.options import Options as FFOptions
from selenium.webdriver.support.select import Select
from InterfaceAuto.commonalKeys import syspublic
from configuration.logger import logger


class Web():
    """
    Creator：Dou
    封装web关键字

    """

    def __init__(self,writer):
        self.driver = None
        self.writer=writer     # 写入Excel对象
        self.row=0             # 记录关键字运行时,写入Excel的行
        self.e=None            # 保存元素失败异常信息
        self.verify=None       # 验证码识别

    def openBrowser(self, browsername="chrome", driverPath=""):
        """
        打开浏览器
        :param browsername: 浏览器
        :param driverPath: driver路径
        :return:
        """
        try:
            if browsername is None or browsername == "" or browsername == "chrome":
                # 使用用户文件加载缓存和配置Chrome的安装路径
                chromeOption = Options()
                # 获取用户文件路径
                userfile = os.environ["USERPROFILE"]
                # 添加用户文件配置. 这里填的是自己本地的地址
                chromeOption.add_argument("--user-data-dir=%s\\AppData\\Local\\Google\\Chrome\\User Dataf" % userfile)

                # 配置chrome安装路径
                # option.binary_location = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"

                # 如果driverPath=None, 就去找项目里面的driver, 不是空的就去找环境变量里面的
                if driverPath == "":
                    driverPath = "./webAuto/driver/chromedriver.exe"
                self.driver = webdriver.Chrome(options=chromeOption, executable_path=driverPath)
                # self.driver.find_element_by_xpath().clear()
            # 打开火狐浏览器
            elif browsername == "firefox":
                # 加载火狐配置文件
                Fprofile = r"火狐的安装路径"
                opt = webdriver.FirefoxOptions
                opt.profile = Fprofile
                if driverPath == "":
                    # 根据自己项目配置Path填写
                    driverPath = "./lib/friefoxdriver.exe"
                self.driver = webdriver.Firefox(friefoxoption=opt, executable_path=driverPath)

            # 隐式等待. 触发条件，有find_element的地方都会执行
            self.driver.implicitly_wait(3)
            self.__writerexcel(True, "打开浏览器成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False,"打开浏览器失败：")
            self.__writerexcel(False,traceback.format_exc())
            self.writer.save_close()
            # 退出运行, 浏览器打开失败了也没有执行Excel的必要了
            exit(-1)

    def get_url(self, url):
        """
        输入对应URL
        :param url:  路径地址
        :return:  True or False
        """
        if self.driver is None:
            self.__writerexcel(False,"driver不存在")
            return False
        try:
            self.driver.get(url)
            self.__writerexcel(True,"访问URL成功")
            return True
        except Exception as e:
            self.__writerexcel(False,"访问URL失败请检查")
            return  False

    def click(self, locateStatement):
        """
        点击方法
        :param locateStatement: 定位表达式
        :return:
        """

        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False,self.e)
            return False
        try:
            ele.click()
            self.__writerexcel(True,"click成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False,traceback.format_exc())
            return False

    def input(self, locateStatement, content):
        """
        输入内容
        :param locateStatement: 定义表达式
        :param content: 输入的内容
        :return:
        """

        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            ele.clear()
            ele.send_keys(content)
            self.__writerexcel(True, "输入成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def input_file(self, locateStatement, content):
        """
        上传文件
        :param locateStatement: 定义表达式
        :param content: 输入的内容
        :return:
        """

        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            content = syspublic.path + "/webAuto/picture/" + content
            ele.send_keys(content)
            self.__writerexcel(True, "上传文件成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def get_image(self,locateStatement,filename=""):
        """
        获取验证码截图
        :param locateStatement: 定位器
        :param filename: 截图后保存的名字
        :return: true or False
        """
        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False

        if filename == "":
            filename="verify"

        try:
            filename = "./webAuto/picture" + filename + ".png"
            ele.screenshot(filename)
            self.__writerexcel(True, "截图成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def into_iframe(self,locateStatement):
        """
        进入iframe
        :param locateStatement:  定位表达式
        :return: True or False
        """
        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            self.driver.switch_to_frame(ele)
            self.__writerexcel(True, "进入iframe成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def exit_iframe(self):
        """
        退出iframe
        :param locateStatement: 定位表达式
        :return: True or False
        """
        try:
            self.driver.switch_to.default_content()
            self.__writerexcel(True, "退出iframe成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def get_text(self, locateStatement, params):
        """
        获取元素文本内容，并保存后为关联后参数名
        :param locateStatement: 定义表达式
        :param params: 保存后的参数名
        :return: true or false
        """

        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            text=ele.text
            # 设置到关联字典里面
            syspublic.relations[params] = text
            self.__writerexcel(True, syspublic.relations[params])
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def assert_contains(self, expect, actual):
        """
        断言包含某个文本内容
        :param expect: 预期结果
        :param actual: 实际结果
        :return: True or False
        """
        # 关联实际结果
        actual = self.__getrelations(actual)
        expect = self.__getrelations(expect)
        if actual.__contains__(str(expect)):
            self.__writerexcel(True, actual)
            return True

        else:
            self.__writerexcel(False, actual)
            return False

    def __getrelations(self, params):
        """
        使用关联
        :param params: 需要关联的参数
        :return:  关联后的字符串
        """
        if params is None:
            return None

        for key in syspublic.relations.keys():
            params = params.replace('{' + key + '}', str(syspublic.relations[key]))
        return params

    def js_click(self, locator):
        """
        点击a标签，针对selenium点击不了的情况
        （点击a标签触发js事件的，JavaScript:void(0);）
        :param locator: 定位器
        :return: 点击成功/失败
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False

        try:
            self.driver.execute_script("$(arguments[0]).click()", ele)
            self.__writerexcel(True, "点击成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def run_js(self, jslocattion):
        """
        使用JS操作页面滚动
        :param jslocattion: JS定位表达式
        :return: True or False
        """

        try:
            time.sleep(2)
            self.driver.execute_script(jslocattion)
            self.__writerexcel(True, "点击成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, traceback.format_exc())
            return False

    def moveto_ele(self,locateStatement):
        """
        悬停方法
        :param locateStatement:  定位表达式
        :return:
        """

        ele = self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            ActionChains(self.driver).move_to_element(ele).perform()
            self.__writerexcel(True, "悬停成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False,"悬停失败：")
            self.__writerexcel(False, traceback.format_exc())
            return False

    def select_index(self,locateStatement,indexparam):
        """
        下拉菜单索引定位
        :param locateStatement: default xpath
        :param indexparam: index参数
        :return:
        """

        ele=self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            Select(ele).select_by_index(indexparam)
            self.__writerexcel(True, "select_index成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, "select_index失败：")
            self.__writerexcel(False, traceback.format_exc())
            return False

    def select_value(self,locateStatement,vauleparam):
        """
        下拉菜单vaule定位
        :param locateStatement: 定位表达式
        :param vauleparam: value参数
        :return:
        """

        ele=self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            Select(ele).select_by_value(vauleparam)
            self.__writerexcel(True, "select_value成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, "select_value失败：")
            self.__writerexcel(False, traceback.format_exc())
            return False

    def select_text(self,locateStatement,text):
        """
        下拉菜单文本定位方式
        :param locateStatement: 定位表达式
        :param text: 文本内容
        :return:
        """

        ele=self.__find_ele(locateStatement)
        if ele is None:
            self.__writerexcel(False, self.e)
            return False
        try:
            Select(ele).select_by_visible_text(text)
            self.__writerexcel(True, "select_text成功")
            return True
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, "select_text失败：")
            self.__writerexcel(False, traceback.format_exc())
            return False

    def switch_windows(self, index=""):
        """
        切换窗口
        :param index: 窗口的下标
        :return: True or False
        """

        if index == "":
            index = 0
        try:
            # 获取所有窗口handles(列表)，获取到窗口的名字可以根据窗口的名字来切换窗口
            hands=self.driver.window_handles
            # 切换窗口
            self.driver.switch_to_window(hands[int(index)])
            self.__writerexcel(True, "切换窗口成功")
        except Exception as e:
            logger.exception(e)
            self.__writerexcel(False, "switch_windows失败：")
            self.__writerexcel(False, traceback.format_exc())
            return False

    def sleep(self, t):
        """
        强制等待
        :param t: 时间，单位s
        :return: 返回成功失败
        """
        try:
            time.sleep(int(t))
            self.__writerexcel(True, "等待成功")
            return True
        except Exception as e:
            self.__writerexcel(False, traceback.format_exc())
            return False

    def quit(self):
        """
        关闭浏览器
        :return:
        """
        try:
            self.driver.quit()
            self.__writerexcel(True,"退出成功")
            return True
        except Exception as e:
            self.__writerexcel(False,traceback.format_exc())
            return False

    def __find_ele(self, locate):
        """
        通过定位器找元素
        :param locate: xpath,id,name default is xpath 如果你要添加其它定位方式自行添加就好
        :return: 返回找到的元素
        """
        try:
            if locate.startswith("xpath="):
                locate = locate[locate.find('=') + 1:]
                ele = self.driver.find_element_by_xpath(locate)
            elif locate.startswith("id="):
                locate = locate[locate.find('=') + 1:]
                ele = self.driver.find_element_by_id(locate)
            elif locate.startswith("name="):
                locate = locate[locate.find('=') + 1:]
                ele = self.driver.find_element_by_name(locate)
            else:
                ele = self.driver.find_element_by_xpath(locate)
        except Exception as e:
            self.e=traceback.format_exc()
            return None
        return ele

    def __writerexcel(self, status, msg):
        """
        写入关键字运行结果
        :param status: 运行状态
        :param msg: 实际结果

        """
        if status is True:
            self.writer.write(self.row, 7, "PASS", 3)
        else:
            self.writer.write(self.row, 7, "FAIL", 2)
        self.writer.write(self.row, 8, str(msg))